#include <string>
#include <iostream>
#include <easyhook.h>
#include <tchar.h>
#include <Windows.h>

using namespace std;
#pragma comment(lib, "Winmm.lib")

BOOL WINAPI myBeepHook(DWORD dwFreq, DWORD dwDuration);
BOOL WINAPI TGHookQueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount);
VOID WINAPI TGHookGetSystemTimeAsFileTime(__out LPFILETIME lpSystemTimeAsFileTime);
DWORD WINAPI TGHookTimeGetTime();
DWORD WINAPI TGHookGetTickCount();

BOOL WINAPI myBeepHook(DWORD dwFreq, DWORD dwDuration)
{
    cout << "\n****All your beeps belong to us!\n\n";
    return Beep(dwFreq + 800, dwDuration);
}

BOOL WINAPI TGHookQueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount) {
    cout << "\n****All your QueryPerformanceCounters belong to us!\n\n";
    return QueryPerformanceCounter(lpPerformanceCount);
}

VOID WINAPI TGHookGetSystemTimeAsFileTime(__out LPFILETIME lpSystemTimeAsFileTime) {
    cout << "\n****All your GetSystemTimeAsFileTimes belong to us!\n\n";
    return GetSystemTimeAsFileTime(lpSystemTimeAsFileTime);
}

DWORD WINAPI TGHookTimeGetTime() {
    cout << "\n****All your timeGetTimes belong to us!\n\n";
    return timeGetTime();
}

DWORD WINAPI TGHookGetTickCount() {
    cout << "\n****All your GetTickCount belong to us!\n\n";
    return GetTickCount();
}

int _tmain(int argc, _TCHAR* argv[])
{
    HOOK_TRACE_INFO hHook = { NULL }; // keep track of our hook
    cout << "\n";
    cout << GetProcAddress(GetModuleHandle(TEXT("kernel32")), "Beep");
    
    // Install the hook
    
    {
        NTSTATUS result = LhInstallHook(
            GetProcAddress(GetModuleHandle(TEXT("kernel32")), "Beep"), 
            myBeepHook, 
            NULL, 
            &hHook);
        if (FAILED(result))
        {
            wstring s(RtlGetLastErrorString());
            wcout << "Failed to install hook: ";
            wcout << s;
            cout << "\n\nPress any key to exit.";
            cin.get();
            return -1;
        }

        cout << "Beep after hook installed but not enabled.\n";
        Beep(500, 500);

        cout << "Activating hook for current thread only.\n";
        // If the threadId in the ACL is set to 0, 
        // then internally EasyHook uses GetCurrentThreadId()
        ULONG ACLEntries[1] = { 0 };
        LhSetInclusiveACL(ACLEntries, 1, &hHook);

        cout << "Beep after hook enabled.\n";
        Beep(500, 500);

        cout << "Uninstall hook\n";
        LhUninstallHook(&hHook);

        cout << "Beep after hook uninstalled\n";
        Beep(500, 500);
    }

    //----------------------------//
    {
        NTSTATUS result = LhInstallHook(
            GetProcAddress(GetModuleHandle(TEXT("kernel32")), "QueryPerformanceCounter"), 
            TGHookQueryPerformanceCounter, 
            NULL, 
            &hHook);
        if (FAILED(result))
        {
            wstring s(RtlGetLastErrorString());
            wcout << "Failed to install hook: ";
            wcout << s;
            cout << "\n\nPress any key to exit.";
            cin.get();
            return -1;
        }

        LARGE_INTEGER nLastTime;

        cout << "QueryPerformanceCounter after hook installed but not enabled.\n";
        QueryPerformanceCounter(&nLastTime);

        cout << "Activating hook for current thread only.\n";
        // If the threadId in the ACL is set to 0, 
        // then internally EasyHook uses GetCurrentThreadId()
        ULONG ACLEntries[1] = { 0 };
        LhSetInclusiveACL(ACLEntries, 1, &hHook);

        cout << "QueryPerformanceCounter after hook enabled.\n";
        QueryPerformanceCounter(&nLastTime);

        cout << "Uninstall hook\n";
        LhUninstallHook(&hHook);

        cout << "QueryPerformanceCounter after hook uninstalled\n";
        QueryPerformanceCounter(&nLastTime);
    }
    
    //----------------------------//

     {
        NTSTATUS result = LhInstallHook(
            GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetSystemTimeAsFileTime"), 
            TGHookGetSystemTimeAsFileTime, 
            NULL, 
            &hHook);
        if (FAILED(result))
        {
            wstring s(RtlGetLastErrorString());
            wcout << "Failed to install hook: ";
            wcout << s;
            cout << "\n\nPress any key to exit.";
            cin.get();
            return -1;
        }

        FILETIME nLastTime;

        cout << "GetSystemTimeAsFileTime after hook installed but not enabled.\n";
        GetSystemTimeAsFileTime(&nLastTime);

        cout << "Activating hook for current thread only.\n";
        // If the threadId in the ACL is set to 0, 
        // then internally EasyHook uses GetCurrentThreadId()
        ULONG ACLEntries[1] = { 0 };
        LhSetInclusiveACL(ACLEntries, 1, &hHook);

        cout << "GetSystemTimeAsFileTime after hook enabled.\n";
        GetSystemTimeAsFileTime(&nLastTime);

        cout << "Uninstall hook\n";
        LhUninstallHook(&hHook);

        cout << "GetSystemTimeAsFileTime after hook uninstalled\n";
        GetSystemTimeAsFileTime(&nLastTime);
    }

    //----------------------------//

    //----------------------------//

     {
        NTSTATUS result = LhInstallHook(
            GetProcAddress(GetModuleHandle(TEXT("Winmm")), "timeGetTime"), 
            TGHookTimeGetTime, 
            NULL, 
            &hHook);
        if (FAILED(result))
        {
            wstring s(RtlGetLastErrorString());
            wcout << "Failed to install hook: ";
            wcout << s;
            cout << "\n\nPress any key to exit.";
            cin.get();
            return -1;
        }

        cout << "timeGetTime after hook installed but not enabled.\n";
        timeGetTime();

        cout << "Activating hook for current thread only.\n";
        // If the threadId in the ACL is set to 0, 
        // then internally EasyHook uses GetCurrentThreadId()
        ULONG ACLEntries[1] = { 0 };
        LhSetInclusiveACL(ACLEntries, 1, &hHook);

        cout << "timeGetTime after hook enabled.\n";
        timeGetTime();

        cout << "Uninstall hook\n";
        LhUninstallHook(&hHook);

        cout << "timeGetTime after hook uninstalled\n";
        timeGetTime();
    }

    //----------------------------//
//----------------------------//

     {
        NTSTATUS result = LhInstallHook(
            GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetTickCount"), 
            TGHookGetTickCount, 
            NULL, 
            &hHook);
        if (FAILED(result))
        {
            wstring s(RtlGetLastErrorString());
            wcout << "Failed to install hook: ";
            wcout << s;
            cout << "\n\nPress any key to exit.";
            cin.get();
            return -1;
        }

        cout << "GetTickCount after hook installed but not enabled.\n";
        GetTickCount();

        cout << "Activating hook for current thread only.\n";
        // If the threadId in the ACL is set to 0, 
        // then internally EasyHook uses GetCurrentThreadId()
        ULONG ACLEntries[1] = { 0 };
        LhSetInclusiveACL(ACLEntries, 1, &hHook);

        cout << "GetTickCount after hook enabled.\n";
        GetTickCount();

        cout << "Uninstall hook\n";
        LhUninstallHook(&hHook);

        cout << "GetTickCount after hook uninstalled\n";
        GetTickCount();
    }

    //----------------------------//

    cout << "\n\nRestore ALL entry points of pending removals issued by LhUninstallHook()\n";
    LhWaitForPendingRemovals();

    cout << "Press any key to exit.";
    cin.get();

    return 0;
}